package com.imc.platform.base.pay.controller;

import com.alibaba.fastjson.JSON;
import com.imc.api.attence.dao.repository.LessonRepository;
import com.imc.api.attence.pojo.Lesson;
import com.imc.api.order.pojo.Order;
import com.imc.api.order.pojo.UserOrgAccount;
import com.imc.api.order.repository.IUserOrgAccountRepository;
import com.imc.api.order.service.WxOrderService;
import com.imc.api.order.tuple.ConfirmOrder;
import com.imc.api.shopmall.service.ShopMallService;
import com.imc.core.annotation.Logs;
import com.imc.core.config.pay.PayConfig;
import com.imc.core.utils.AESUtils;
import com.imc.core.utils.MysqlUtil;
import com.imc.core.utils.XmlUtils;
import com.imc.platform.base.pay.http.WxPayService;
import com.imc.platform.base.pay.http.tuple.PayDto;
import com.imc.platform.base.pay.http.tuple.PrePayBody;
import com.imc.platform.base.pay.http.tuple.PrePayDto;
import com.imc.platform.base.pay.http.tuple.PrePayParams;
import com.imc.platform.base.pay.service.PayService;
import com.imc.platform.base.user.dao.mapper.IUserMapper;
import com.imc.platform.base.user.pojo.User;
import com.twp.common.tuple.ResultDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.security.Principal;
import java.util.Date;
import java.util.List;

/**
 * Created by tanweiping on 2018/9/4.
 */
@Slf4j
@Controller
public class WeixinPayController {

    @Autowired
    WxPayService wxPayService;

    @Autowired
    AESUtils aesUtils;

    @Autowired
    MysqlUtil mysqlUtil;

    @Autowired
    PayConfig payConfig;

    @Autowired
    PayService payService;

    @Autowired
    ShopMallService shopMallService;

    @Autowired
    LessonRepository lessonRepository;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    IUserOrgAccountRepository iUserOrgAccountRepository;

    @Autowired
    IUserMapper iUserMapper;

    /*
    * tanweiping  2018/11/20 10:13
    * 方法描述：课程立即下单
    */
    @Logs
    @ResponseBody
    @PostMapping("/api/wx/prepayImmediately/{lessonId}")
    public ResultDTO prepayImmediately(
            Principal principal,
            HttpServletRequest request,
            @PathVariable String lessonId,
            @RequestBody PrePayBody prePayBody,
            @RequestParam(defaultValue = "1")int num
    ){
        String userSubId = prePayBody.getUserSubId();
        List<String> scheduleIdList = prePayBody.getScheduleIdList();

        PrePayParams prePayParams = prePayBody.getPrePayParams();

        User user = mysqlUtil.getUserByLoginName(principal.getName());
        log.info(user.getLoginName()+"购买了"+lessonId+"的课程,购买了共"+num+"节课");
        ResultDTO resultDTO = ResultDTO.builder().build();

        Lesson  lesson = lessonRepository.findOne(Integer.parseInt(lessonId));

        /*
        1.判断库存
         */
        if (lesson.getStock().intValue()<=0){
            resultDTO.setIsSuccess(false);
            resultDTO.setMessage("课程库存不足");
            return resultDTO;
        }

        if (lesson.getPayType().equals("3")){
            /*
            课时结算
             */
            /*
            判断个人学校课时储备
             */
            UserOrgAccount userOrgAccount = iUserOrgAccountRepository.findAllByUserIdAndOrgId(String.valueOf(user.getId()),String.valueOf(lesson.getOrgId()));

            if (userOrgAccount==null||userOrgAccount.getLessonAccount().intValue()<num*scheduleIdList.size()){
                resultDTO.setIsSuccess(false);
                resultDTO.setMessage("您储备的账户课时不足，请及时充值");
                return resultDTO;
            }
            User loginUser=(User)request.getSession().getAttribute("currentUser");
            /*
            结算课时
             */
            try {
                wxOrderService.postOrder(user,lesson,num,scheduleIdList,userOrgAccount,userSubId,loginUser.getLoginName());

                iUserMapper.updateOrgIdByUserSubId(String.valueOf(lesson.getOrgId()),userSubId);

            }catch (Exception e){
                e.printStackTrace();
                resultDTO.setIsSuccess(false);
                resultDTO.setMessage("课时结算失败");
            }
            return resultDTO;
        }
        int size = scheduleIdList==null?Integer.parseInt(lesson.getLessonDate()):scheduleIdList.size();
        int totalFee = new BigDecimal(lesson.getGroupPrice())
                .multiply(
                        new BigDecimal(100*num*size)
                ).divide(new BigDecimal(lesson.getLessonDate()))
                .intValue();
        prePayParams.setTotal_fee(totalFee);

        prePayParams.setSpbill_create_ip(request.getRemoteAddr());
        prePayParams.setAttach(payConfig.getOrgName());
        if (StringUtils.isEmpty(prePayParams.getBody())){
            prePayParams.setBody(payConfig.getOrgName()+":"+lesson.getLessonName());
        }
        if (StringUtils.isEmpty(prePayParams.getDetail())) {
            prePayParams.setDetail(payConfig.getOrgName()+":"+lesson.getMDesc());
        }

        prePayParams.setNotify_url(payConfig.getNotifyUrl());
        prePayParams.setTrade_type("JSAPI");
        String tradeNo = String.valueOf(new Date().getTime());
        prePayParams.setOut_trade_no(tradeNo);
        prePayParams.setOpenid(user.getOpenId());

        prePayParams.setSign(prePayParams.getMySign(payConfig.getKey()));
        try{
            PayDto payDto = payService.prePayParams(prePayParams,user,lesson,num,scheduleIdList,userSubId);
            resultDTO.setData(
                    payDto
            );
            log.info("payDto:"+JSON.toJSONString(payDto));
        }catch (Exception e){
            e.printStackTrace();
        }
        return resultDTO;
    }

    @Logs
    @ResponseBody
    @PostMapping("/api/wx/prepay/{orderId}")
    public ResultDTO prepay(Principal principal, HttpServletRequest request,@PathVariable String orderId, @RequestBody PrePayParams prePayParams){

        ResultDTO resultDTOV = payService.verify(String.valueOf(prePayParams.getTotal_fee()),orderId);
        if (!resultDTOV.getIsSuccess()) return resultDTOV;

        User user = mysqlUtil.getUserByLoginName(principal.getName());

        ResultDTO resultDTO = ResultDTO.builder().build();
        prePayParams.setSpbill_create_ip(request.getRemoteAddr());
        prePayParams.setAttach(payConfig.getOrgName());
        if (StringUtils.isEmpty(prePayParams.getBody())){
            prePayParams.setBody(payConfig.getOrgName()+"下单支付");
        }
        if (StringUtils.isEmpty(prePayParams.getDetail())) {
            prePayParams.setDetail(payConfig.getOrgName() + "下单支付");
        }

        prePayParams.setNotify_url(payConfig.getNotifyUrl());
        prePayParams.setTrade_type("JSAPI");
        String tradeNo = String.valueOf(new Date().getTime());
        prePayParams.setOut_trade_no(tradeNo);
        prePayParams.setOpenid(user.getOpenId());

        prePayParams.setSign(prePayParams.getMySign(payConfig.getKey()));
        PrePayDto prePayDto;
        try{
            String prePayDto_ = wxPayService.PrePay(
                    prePayParams
            );
            prePayDto = XmlUtils.xmlToBean(prePayDto_,PrePayDto.class);
            if (
                    !prePayDto.getReturn_code().toLowerCase().equals("SUCCESS".toLowerCase())
                ||
                    !prePayDto.getResult_code().toLowerCase().equals("SUCCESS".toLowerCase())
                    ){
                resultDTO.setIsSuccess(false);
                resultDTO.setMessage(prePayDto.getReturn_msg());
                return resultDTO;
            }

            /*
            order回写
             */
            Order order = (Order)resultDTOV.getData();
            order.setStatus(1);
            order.setPrepayId(prePayDto.getPrepay_id());
            order.setTradeType(prePayDto.getTrade_type());
            order.setTradeNo(tradeNo);
            wxOrderService.save(order);
            shopMallService.cleanShopMallByOrder(principal,Integer.parseInt(orderId));

            PayDto payDto =PayDto.builder()
                    .appId(prePayDto.getAppid())
                    .prepay_id(prePayDto.getPrepay_id())
                    .build();
                    payDto.setPaySign(payDto.getMyPaySign(payConfig.getKey()));
            resultDTO.setData(
                    payDto
            );
            log.info("prePayDto:"+JSON.toJSONString(prePayDto));
        }catch (Exception e){
            log.error("error:"+e.toString());
        }
        return resultDTO;
    }

    /*
            <xml><appid><![CDATA[wxcac3896371129ae1]]></appid>
                <attach><![CDATA[桃李舞苑]]></attach>
                <bank_type><![CDATA[CFT]]></bank_type>
                <cash_fee><![CDATA[1]]></cash_fee>
                <fee_type><![CDATA[CNY]]></fee_type>
                <is_subscribe><![CDATA[N]]></is_subscribe>
                <mch_id><![CDATA[1513423541]]></mch_id>
                <nonce_str><![CDATA[f8a69144-5ba4-40]]></nonce_str>
                <openid><![CDATA[odJAr5GiA5kEss7ZlwQtCCqzN0Po]]></openid>
                <out_trade_no><![CDATA[1538200815093]]></out_trade_no>
                <result_code><![CDATA[SUCCESS]]></result_code>
                <return_code><![CDATA[SUCCESS]]></return_code>
                <sign><![CDATA[73CCA0D6090958366E46586653A1F251]]></sign>
                <time_end><![CDATA[20180929140037]]></time_end>
                <total_fee>1</total_fee>
                <trade_type><![CDATA[JSAPI]]></trade_type>
                <transaction_id><![CDATA[4200000192201809291017913628]]></transaction_id>
            </xml>
     */
    @Logs
    @ResponseBody
    @RequestMapping(
            value = "/api/callback/wx/notify",
            method = {RequestMethod.GET, RequestMethod.POST}
    )
    public String wxNotify(HttpServletRequest request){
        log.info("进入异步通知");
        /**
         * 订单支付异步通知
         */
            String resXml="";
            try{
                //
                InputStream is = request.getInputStream();
                //将InputStream转换成String
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                StringBuilder sb = new StringBuilder();
                String line = null;
                try {
                    while ((line = reader.readLine()) != null) {
                        sb.append(line + "\n");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                resXml=sb.toString();
                System.err.println(resXml);
                String result = payService.payBack(resXml);
//            return "<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>";
                return result;
            }catch (Exception e){
                log.error("手机支付回调通知失败",e);
                String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                return result;
            }
        }

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public static class ReqTuple{
        String businessKey;
        String req_info;
        String encrypted;
        String session_key;
        String iv;
    }


    /**
    *QY 2018/9/12 19:11
    *方法描述：退款订单信息解密
    **/
    @Logs
    @RequestMapping(value = "/api/wx/payFail",method = RequestMethod.POST)
    @ResponseBody
    public ResultDTO payFail(@RequestBody ReqTuple reqTuple){
        ResultDTO resultDTO = ResultDTO.builder().build();
        try {
            if("".equals(reqTuple.businessKey) && null !=reqTuple.businessKey){
                resultDTO.setData(AESUtils.decryptData(reqTuple.businessKey,reqTuple.req_info));
                resultDTO.setIsSuccess(true);
                resultDTO.setMessage("解密成功");
            }else {
                resultDTO.setIsSuccess(false);
                resultDTO.setMessage("商户KEY为空");
            }
        }catch (Exception e){
            resultDTO.setIsSuccess(false);
            resultDTO.setMessage(e.getMessage());
        }
        return resultDTO;
    }

}
